home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 076-100 / disk_084 / audiotools / original.article.text < prev    next >
Text File  |  1992-05-06  |  19KB  |  426 lines

  1. The Audio Device On The Amiga
  2. -----------------------------
  3. May, 1986, somebody asks:  "Why couldn't they have made audio easier to use?"
  4.  
  5. Is it really so difficult, I ask myself.  After all, it seems pretty
  6. thoroughly documented.  But then again, why are so few people using
  7. audio so far if it is supposed to be so good on the Amiga.  But I'm
  8. really busy trying to document other things so I leave audio to the
  9. experts.  As help is requested, it appears that the designer of the
  10. audio device is advising people in person.   I guess that whoever
  11. needs help is getting directly to him.
  12.  
  13. Fast forward to November, 1986.  I am not at Amiga any more.
  14. I'm consulting for a couple of other places and doing the Programmers'
  15. Guide To The Amiga in whatever spare time I have left.  Comes the
  16. time to do an audio chapter.  Hmmm, the ROM Kernel stuff
  17. describes a lot of features, but demonstrates only a few of them.
  18. And it goes directly to the hardware.  I don't want to do that!
  19.  
  20. My editor recommends another Amiga book that seems to have an "inside look"
  21. at the audio.  So I got it and, oh no, it goes directly to the hardware
  22. too!  What I want to do is queue up several sounds, and have
  23. the the audio system play them sequentially while my task goes on to do 
  24. something else.  Going directly to the hardware meant the audio device
  25. will neither count cycles for me nor queue sounds for automatic
  26. play.
  27.  
  28. Sound queueing could be done using the audio device command
  29. called CMD_WRITE, but at first I found no examples that used the
  30. CMD_WRITE command.  Later, after several false starts (and after
  31. completing the audio chapter and most of the rest of the book) I
  32. finally discovered an example program on Usenet (reposted from BIX)
  33. that used CMD_WRITE.  Some pieces of that program, along with what
  34. I developed subsequent to the audio chapter, appear here.
  35.  
  36. I simply wanted my main program to look like this:
  37.  
  38.     main()
  39.     {    
  40.     /* ... (program-stuff) ... */
  41.  
  42.     InitAudio();    /* initialize everything */
  43.  
  44.     channel = GetChannel(-1);
  45.     if(channel != -1)
  46.     {
  47.         PlayNote(channel, waveform, note_no, volume, duration);
  48.         /* ... (more PlayNotes) ... */
  49.     }
  50.     /* do non-audio things here */
  51.  
  52.     FreeChannel(channel);
  53.     FinishAudio();    /* close everything down */
  54.     }
  55.  
  56. THAT seemed to make it simple, and it seemed to be what I wanted (and what
  57. others had been asking for).   The details of device access and message passing
  58. are buried in a subroutine somewhere, where a person need not deal with it.
  59. After I created some of these routines I tested them on a few cases and 
  60. they seem to be what people wanted, so here they are.
  61.  
  62. The functions you see above are provided in 
  63. this article, with other support functions for the audio device.
  64. By examining the source code I've provided, you will see
  65. just how to communicate with the audio device and you
  66. may be able to add your own enhancements to these techniques.
  67.  
  68. At the end of the article, you'll find a list of some of the 
  69. enhancements I expect to install by the time this article actually
  70. appears in print, as well as other features that people have requested.
  71.  
  72. Note:  If not otherwise stated, all parameters passed to the routines and
  73. passed back as return values are LONG integers (32-bits).  Sometimes
  74. a pointer (also 32-bits) is used, and is shown as such.
  75.  
  76. The Functions, Explained
  77. ------------------------
  78. 1.  gotchannel = GetChannel(channel);
  79.  
  80.     channel -  any number from 0 to 3, corresponding to a specific 
  81.           hardware channel on the Amiga.  If you ask for channel 
  82.           number -1, it means get ANY channel that is available.  
  83.           The function GetChannel returns the channel number, or 
  84.           returns -1 if none are available to you.
  85.  
  86. 2.  PlayNote(channel,waveform,note_no,volume,duration,priority,message);
  87.  
  88.     channel - a channel that you already own.  If you 
  89.           don't own it, the note simply will not play.
  90.  
  91.     waveform - a pointer to the start of a waveform table 
  92.           that contains 256 samples of a single wave 
  93.           of your sound.  Sample values range from
  94.           -128 to +127.  The waveform table also includes
  95.           copies of the same waveform, each having fewer 
  96.           and fewer samples in the table (128 samples, 
  97.           64, 32 and so on).  
  98.  
  99.           This waveform table lets us stay within
  100.           the allowable limits of the Amiga audio hardware.
  101.           In particular, period values of 127 through 500
  102.           are the values that lets the Amiga output the
  103.           best quality audio.  To get an output that is
  104.           of a high frequency, since the period values
  105.           are limited, each wave of the waveform must be
  106.           output more quickly.  Thus the table with 
  107.           several copies of the waveform, each having
  108.           different numbers of samples.  See the source
  109.           code for MakeWaves to see how the tables are built.
  110.  
  111.     Note Number - Notes are numbered from 0 to 95, structured
  112.           as 8 octaves of 12 notes each.  Each octave has
  113.           its own waveform table entry having a length
  114.           appropriate to that octave.
  115.  
  116.     Volume -  Takes a value from 0 to 64 where 0 is minimum.
  117.           
  118.     Duration - specified in 1000ths of a second.  Five Hundred
  119.           thousandths of a second, for example, is one-half
  120.           of a second.  The audio device accepts a command
  121.           to output a specific number of cycles of a waveform.
  122.           I calculate the frequency (in cycles per second)
  123.           from the note number, then multiply by Duration
  124.           and divide by 1000, yielding the correct number
  125.           of cycles for that frequency.  Thus all notes
  126.           play for the correct time.
  127.  
  128.     Priority - [NOT IMPLEMENTED YET].  If priority is 0, 
  129.           just queue the note.  If less than 0, flush all 
  130.           current requests for this channel and start this
  131.           note only.  If greater than 0, do not flush... 
  132.           the priority value is only going to be used to
  133.           identify the note number to you when the note
  134.           begins to play.  
  135.  
  136.     Message - [NOT IMPLEMENTED YET].   Audiotools can send
  137.           you a message that contains an identifier of 
  138.           your choice (the priority value) to let your
  139.           task know that this note has just begun to
  140.           play.  On receiving the message, your task
  141.           must reply to it so that the audiotools can
  142.           reuse or deallocate the message memory.
  143.  
  144. 3.  FreeChannel(channel) - frees a channel that you own to let another task
  145.           (or your own task, later) use the channel.
  146.  
  147. 4.  InitAudio()
  148. 5.  FinishAudio() - These functions take care of the background work,
  149.          such as opening and closing the audio device.
  150.  
  151. By using these routines, you do not have to deal with the audio device
  152. at all.   You need not allocate and initialize message blocks and so on.
  153. All of this is built into the support routines and associated global variables.
  154.  
  155. By using the routines, though, you add some additional overhead to 
  156. accessing the audio device.  If you are designing a high performance
  157. audio routine, you just may have to lock the channels and go directly
  158. to the hardware.  For that kind of thing, you have the ROM Kernel
  159. examples to guide you.
  160.  
  161. But for the rest of us, who just need to BEEP at somebody, these
  162. routines make the access just a bit simpler (and provide a
  163. functional jumping off point for further audio development).
  164. You could also get rid of the subroutine call overhead by copying
  165. appropriate portions of code directly into your main program.
  166.  
  167. Note: PlayNote is asynchronous.  This means that it queues up a note to be 
  168. played by the audio device and then returns to the calling program
  169. immediately.  (It does not wait for the note to be finished before
  170. it returns to the caller).  ALL other functions in this article
  171. are synchronous.  That is, the function is performed entirely before
  172. your program goes on to do something else.
  173.  
  174.  
  175. What The Sample (main) Program Does
  176. -----------------------------------
  177. Using the above functions, main simply plays a few notes through each
  178. channel, in each of the waveforms: sawtooth, triangle and square waves.
  179. All 4 channels are active at the same time.  When all notes have completed,
  180. the program exits.
  181.  
  182.  
  183. Support Functions
  184. -----------------
  185. This audio library has the following support functions.
  186.  
  187. 6.  error = StopChannel(channel)
  188. 7.  error = StartChannel(channel) - stop or start a specific channel.
  189.  
  190.        If a CMD_WRITE arrives at a stopped channel, it queues
  191.        and waits for the channel to be started.  A return value
  192.        of 0 means no error.  A return of -1 indicates low memory.
  193.        Any other value is a direct return from io_Error.  See
  194.        devices/audio.h for meanings of other return values.
  195.        StopChannel terminates any CMD_WRITE currently in progress.
  196.  
  197. 8.  error = FlushChannel(channel) - If there are CMD_WRITE's lined up
  198.        to be played, return them all to the caller (flush input).
  199.  
  200. 9.  error = ResetChannel(channel) - reset it to its default values.
  201.        Also means flush a channel's input queue.  
  202.  
  203. 10. stereopair = GetStereoPair(pair) - 
  204.        In the Amiga hardware, audio channels 0 and 3 are connected
  205.        to the Left audio output; audio channels 1 and 2 are connected
  206.        to the Right audio output.  Thus to get a stereo pair, you
  207.        need left-channel and one right-channel.
  208.  
  209.        Specify pair as -1 for ANY stereo pair,
  210.        or specify 0 (for audio channels 0 and 1), 1 (for 0 and 2), 
  211.        2 (for 1 and 3) or 3 (for 2 and 3).  Return value is the pair
  212.        that was available, or -1 if no stereo pair is available.  
  213.        FreeChannel(stereopair) works just as FreeChannel(channel).
  214.  
  215. 11. error = SetPV(channel, period, volume) - set the period and volume of
  216.        a note that is playing currently.  Note that there is only
  217.        a limited range available for the period (roughly 127 to 500)
  218.        so is it more likely that you would use PlayNote instead since
  219.        PlayNote can modify the waveform pointer as well as the other
  220.        parameters.
  221.  
  222.  
  223. Internal Functions
  224. ------------------
  225. The following internal functions are used by the library functions 
  226. shown earlier.   Your programs may, at times, need these functions as well.
  227. These functions create, initialize and free audio device message blocks.  
  228. (I call them IOBs, for I/O Blocks).
  229.  
  230. 12. iob = GetIOB() - allocate or assign an IOAudio structure for use.
  231.       Returns a value of 0 if system is too low on memory.
  232.       If no IOB is available from a specified pool of IOB's,
  233.       then dynamically allocate an IOB and pass back its address.
  234.  
  235.       Note: for more advanced system functions suggested by the users
  236.       group members (shown later in this article), this structure
  237.       may need to be extended to hold additional parameters.
  238.       For now, though, the ExtIOB structure is identical
  239.       to the normal IOAudio structure (created for now by a define
  240.       statement).  This allows us to define an extended version
  241.       of the structure later, with little if any change to 
  242.       existing functions.
  243.  
  244. 13. ReEmployIOB() - look at audio channel reply ports and see if any
  245.       IOB's have returned (are now unemployed) and can therefore 
  246.       be reassigned or deallocated.
  247.      
  248. 14. FreeIOB() - return a finished IOB to the free IOB pool or deallocate
  249.       a dynamically allocated one.
  250.  
  251. 15. InitBlock(iob,channel) - Initialize an IOB for communication with a
  252.       specific channel, default command is CMD_WRITE.  iob is a pointer
  253.        to an IOAudio structure.  Channel is the specific channel for
  254.       which this block is to be initialized (allocation key is the
  255.       critical item).
  256.  
  257. 16. ExpandWave(waveform_pointer) - Takes a pointer to a waveform buffer
  258.       that contains one cycle of a waveform, in 256 consecutive
  259.       bytes, and expands the table to add the same waveform sampled
  260.       128 times at twice the sampling interval, 64 times at 4 times
  261.       the sampling interval, 32 times/16 times/8 times and so on.
  262.  
  263.       NOTE: the wave tables MUST be in CHIP memory otherwise
  264.       the audio device will be unable to play the notes!!!
  265.  
  266.       ExpandWave is associated with MakeWaves() that creates three
  267.       tables total, one containing a sawtooth wave, one a triangle
  268.       wave, and the third contains a square wave.  ExpandWave
  269.       completes the table entries for each waveform.  
  270.       All of the waveforms are left in contiguous memory after the
  271.       first wave, in order of decending sizes (256, 128, 64, ...)
  272.  
  273. MakeWaves, ExpandWave, SetPV and PlayNote are paraphrased versions of
  274. similar routines found in a posting to BIX by Steven A. Bennett.  
  275. Thanks, Steven, for the inspiration on this project.  Steven's posted
  276. article also provided the waveform and period tables I've used, as
  277. well as the excellent explanation of the period value calculation 
  278. that I've quoted (slightly modified) below.
  279.  
  280. As you examine the source code provided, you'll see that the
  281. audio device requires a period value rather than a frequency value.
  282. The period table contains the period value corresponding to the
  283. frequencies of the normal scale (12 notes per octave... see ABasiC
  284. manual, page 138).  You could calculate period yourself from the
  285. formula:
  286.  
  287.     period = Clock / ( samples-per-wave * frequency)
  288.  
  289.     Clock rate is 3,579,545 cycles per second
  290.     
  291. So if you are playing a wave table that contains 32 samples, and
  292. your selected output frequency is to be middle-A (440 hz), 
  293. of the piano the period value must be
  294.  
  295.         3579545 / (32 * 440) = 254.229.
  296.  
  297. <SAB>: "But the audio device only accepts a whole number, so your result 
  298. has to be rounded down to the nearest integer which can result
  299. in a maximum frequency error of about .25%, assuming one uses the
  300. octave for frequency between period 226 and period 428.  (This comes
  301. out to be less than a twentieth step at the shortest period)."
  302.  
  303. <SAB>: "Period values of less than 127 are illegal, as there aren't enough
  304. cycles set aside for audio DMA for anything less.  period values of
  305. greater than 500 or so aren't recommended as the anti-aliasing
  306. filter isn't of much use then, and actually could cause a possible
  307. high pitched overtone, which I'm sure nobody wants.  Thus I am
  308. only going to use SetPV to handle a single octave's range."
  309.  
  310. <SAB>: "Changes of octave are accomplished by doubling or halving the 
  311. number of samples in one cycle of the waveform, so one must, therefore, 
  312. call PlayNote() instead of SetPV()."
  313.  
  314.  
  315. Additional Information About Internal Functions
  316. -----------------------------------------------
  317. For GetIOB, you can control how many structures are allocated for
  318. IOAudio use.   How many audio ioblocks should the system have available for
  319. queueing up notes?   If you want to queue up a whole song 
  320. by using a whole bunch of PlayNote commands and go away to do
  321. something else, it could take a lot of memory!  Once the system 
  322. runs out of these preallocated structures, it must dynamically 
  323. allocate and free memory... this can cause fragmentation of memory space.
  324. You might want to send parts of the song at a time instead of the
  325. whole song.
  326.  
  327. Depending on the variable AUDBUFFERS, defined when the
  328. program is compiled, GetIOB either returns the address of
  329. a buffer in global memory space, named "global"
  330. (in the name field of the I/O message, node area) or
  331. named "dynamic" if GetIOB runs out of AUDBUFFERS global blocks
  332. to use.  The number of dynamic blocks is limited only by the
  333. available system memory (FAST memory, that is non-CHIP memory
  334. is used for the I/O blocks).
  335.  
  336. NOTE:  To be able to use only a standard sized IOAudio structure
  337. for the message passing, I assigned the message mn_Length field
  338. to identify the global blocks.  (As of 1.1 and 1.2, the mn_Length
  339. field is still available for anybody to decide what meaning it has).
  340. To be perfectly safe, as well as to handle the advanced functions
  341. that people have requested, an extended audio block should probably be
  342. used... with a LONG quantity appended to it as the identifier
  343. in place of using mn_Length, as well as a few other fields.  This
  344. change is very likely to be made for the disk version of the tools.
  345. (The structure ExtIOB will be used as an extended version of IOAudio).
  346.  
  347. The Audio Tools And A Test Program
  348. ----------------------------------
  349. Here are the listings that implement the tools described above.
  350. Following the listings are some improvements that have been
  351. suggested.   Whatever I've been able to implement of those 
  352. improvements, as well as this code, appears on the disk mentioned
  353. at the end of the article.
  354.  
  355. I hope these help you to better understand the audio system of
  356. the Amiga.
  357.  
  358. ========================================
  359.  
  360. <Insert All Listings Here>
  361.  
  362. ========================================
  363.  
  364.  
  365. What People Have Suggested
  366. --------------------------
  367. I did a chalk-talk at a developers' group meeting, and showed them what
  368. I was working on for this article.  They suggested the following additions
  369. to what you see described above.
  370.  
  371.     0. Add examples that use the stereo pair; check that
  372.        all error conditions are properly reported ("bullet-proofing").
  373.        (This is numbered "0" because it just has-to-be-done).
  374.  
  375.     1. Implement the Priority and Message fields of PlayNote,
  376.        just as described.
  377.  
  378.     2. Add a PlaySong function that can take a pointer
  379.        to a data structure that describes a song, with
  380.        some of the parameters that PlayNote takes, and
  381.        just play the song automatically.  
  382.  
  383.     3. Add a PlayWave function to handle sampled sounds, such as:
  384.  
  385.          PlayWave(channel,sample_addr,copy,period,repeats,priority,message)
  386.  
  387.        Global variables would be expanded to include a separate 
  388.        ReplyPort for the sampled sounds.  A copy (TRUE/FALSE) 
  389.        parameter would specify (if TRUE) that the sampled_wave should be 
  390.        copied (into chip memory) before queueing it to be played.
  391.        (Only CHIP memory waveforms can be played anyway).  
  392.        If FALSE, it would assume that sample_addr is in chip
  393.        memory and that you will not change the contents of memory
  394.        before the note has completed playing. 
  395.  
  396.     4. Add a PlayFreq function that takes a frequency value instead
  397.        of a note number so that oriental music, for example, not
  398.        based on the same scale we use for a piano, could be played.
  399.        PlayFreq would take exactly the same parameters as PlayNote
  400.        but substitute "frequency" for "note_no".  It would calculate
  401.        which is the longest waveform that can be used for the
  402.        selected frequency and still leave the period value within
  403.        the appropriate range of 127 to 500.
  404.  
  405.     5. Add an implied-rest between notes so that it would sound
  406.        more natural and avoid having to explicitly encode such
  407.        rests into a song structure.
  408.  
  409.     6. Add the ability to specify a slew rate for either volume
  410.        or frequency or both so that notes instead of going
  411.        directly from one setting to another can slide to
  412.        the new setting at a specified rate.  Or perhaps 
  413.        better still, add full ADSR capabilities.
  414.  
  415.        This last one is a little tricky.  It could require
  416.        software interrupts or perhaps even breaking into the
  417.        audio interrupt vector itself.  It will also require
  418.        a data structure larger than the basic IOAudio structure
  419.        to hold these new variables.
  420.  
  421. This article is basically a report on current progress on a continuing
  422. project whose goal is to develop a freely distributable set of license-free
  423. routines that make it easier to use Amiga audio.  I welcome suggestions
  424. as to additional enhancements that might be useful, or code samples
  425. that implement such enhancements.
  426.